#include "SQLLimit.h"
#include "expr/SQLIntegerExpr.h"
#include "../visitor/SQLASTVisitor.h"

SQLLimit::SQLLimit()
{
  by = SQLExpr_list_ptr ();
}

SQLLimit::SQLLimit(int rowCount)
{
  by = SQLExpr_list_ptr ();
  this->setRowCount(SQLIntegerExpr_ptr(new SQLIntegerExpr(rowCount)));
}

SQLLimit::SQLLimit(SQLExpr_ptr rowCount)
{
  by = SQLExpr_list_ptr ();
  this->setRowCount(rowCount);
}

SQLLimit::SQLLimit(SQLExpr_ptr offset, SQLExpr_ptr rowCount)
{
  by = SQLExpr_list_ptr ();
  this->setOffset(offset);
  this->setRowCount(rowCount);
}

SQLExpr_ptr SQLLimit::getRowCount()
{
  return rowCount;
}

void SQLLimit::setRowCount(SQLExpr_ptr rowCount)
{
  if (rowCount != NULL)
  {
    rowCount->setParent(SharedObject(SQLLimit));
  }
  this->rowCount = rowCount;
}

void SQLLimit::setRowCount(int rowCount)
{
  this->setRowCount(SQLIntegerExpr_ptr(new SQLIntegerExpr(rowCount)));
}

SQLExpr_ptr SQLLimit::getOffset()
{
  return offset;
}

void SQLLimit::setOffset(int offset)
{
  this->setOffset(SQLIntegerExpr_ptr(new SQLIntegerExpr(offset)));
}

void SQLLimit::setOffset(SQLExpr_ptr offset)
{
  if (offset != NULL)
  {
    offset->setParent(SharedObject(SQLLimit));
  }
  this->offset = offset;
}

void SQLLimit::merge(SQLLimit_ptr other)
{
  if (other == NULL)
  {
    return;
  }

  if (other->offset != NULL)
  {
    if (this->offset == NULL)
    {
      this->offset = std::dynamic_pointer_cast<SQLExpr>(other->offset->clone());
    }
  }

  if (other->rowCount != NULL)
  {
    if (this->rowCount == NULL)
    {
      this->rowCount = std::dynamic_pointer_cast<SQLExpr>(other->rowCount->clone());
    }
  }

  if (!other->by->empty())
  {
    for (SQLExpr_ptr item : *other->by)
    {
      addBy(std::dynamic_pointer_cast<SQLExpr>(item->clone()));
    }
  }
}

void SQLLimit::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLLimit)))
  {
    if (offset != NULL)
    {
      offset->accept(visitor);
    }

    if (rowCount != NULL)
    {
      rowCount->accept(visitor);
    }

    if (!by->empty())
    {
      for (SQLExpr_ptr item : *by)
      {
        item->accept(visitor);
      }
    }
  }
  visitor->endVisit(SharedObject(SQLLimit));
}

// SQLLimit *SQLLimit::clone()
SQLObject_ptr SQLLimit::clone()
{    
  SQLObject_ptr clone_tmp = SQLLimit_ptr(new SQLLimit());
  SQLLimit_ptr clone_res = std::dynamic_pointer_cast<SQLLimit>(clone_tmp);

  // return ;
  // SQLLimit *x = new SQLLimit();

  if (offset != NULL)
  {
    clone_res->setOffset(std::dynamic_pointer_cast<SQLExpr>(offset->clone()));
  }

  if (rowCount != NULL)
  {
    clone_res->setRowCount(std::dynamic_pointer_cast<SQLExpr>(rowCount->clone()));
  }

  if (!by->empty())
  {
    for (SQLExpr_ptr item : *by)
    {
      clone_res->addBy(item);
    }
  }

  if (!attributes->empty())
  {
    clone_res->attributes = attributes;
  }

  return clone_res;
}

void SQLLimit::addBy(SQLExpr_ptr item)
{
  if (item == NULL)
  {
    return;
  }

  if (by == NULL) {
      by = SQLExpr_list_ptr();
  }
  by->push_back(item);
  item->setParent(SharedObject(SQLLimit));
}

SQLExpr_list_ptr  SQLLimit::getBy()
{
  return by;
}

BOOL_ptr SQLLimit::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (rowCount == expr)
  {
    setRowCount(target);
    return BOOL::TRUE;
  }

  if (offset == expr)
  {
    setOffset(target);
    return BOOL::TRUE;
  }

  return BOOL::FALSE;
}

bool SQLLimit::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == NULL || getClass() != o->getClass())
  {
    return false;
  }

  SQLLimit_ptr limit = std::dynamic_pointer_cast<SQLLimit >(o);

  if (rowCount != NULL ? !(rowCount == limit->rowCount) : limit->rowCount != NULL)
  {
    return false;
  }
  return offset != NULL ? (offset == limit->offset) : limit->offset == NULL;
}

int SQLLimit::hashCode()
{
  int result = rowCount != NULL ? rowCount->hashCode() : 0;
  result = 31 * result + (offset != NULL ? offset->hashCode() : 0);
  return result;
}
